package org.btik.light.mobile.ui.view;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
import org.btik.light.mobile.R;

/**
 * @author lustre
 * @since 2023/4/16 15:31
 */
public class LRSteeringControlView extends View implements View.OnTouchListener {

    private final Paint borderPaint = new Paint();

    private final Paint silderPaint = new Paint();

    private final Paint scalePaint = new Paint();

    private final Paint cursorPaint = new Paint();

    private float width = 220;

    private float height = 100;

    private float sliderWidth = height;

    private float sliderHeight = sliderWidth;

    /**
     * 滑块可以滑动的区间起始 中点的y坐标
     */
    private float availableStart = sliderWidth / 2;

    /**
     * 滑块可以滑动的区间结束 中点的y坐标
     */
    private float availableEnd = width - sliderWidth / 2;

    private float rangeWidth = availableEnd - availableStart;
    private float centX;

    private RectF border;

    private RectF slider;

    private float xOffSet = 0;

    private int value;

    private ValueAnimator positionAnimator;//自动回中的动画

    private OnValueChangeListener onValueChangeListener;

    public LRSteeringControlView(Context context) {
        super(context);
        init(context, null);
    }

    public LRSteeringControlView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public LRSteeringControlView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, @Nullable AttributeSet attrs) {
        if (attrs != null) {
            try (TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.LRSteeringControlView)) {
                int borderColor = typedArray.getColor(R.styleable.LRSteeringControlView_borderColor, Color.GRAY);
                width = typedArray.getDimension(R.styleable.LRSteeringControlView_borderWidth, 100);
                height = typedArray.getDimension(R.styleable.LRSteeringControlView_borderHeight, 220);
                int sliderColor = typedArray.getColor(R.styleable.LRSteeringControlView_sliderColor, Color.LTGRAY);
                sliderWidth = typedArray.getDimension(R.styleable.LRSteeringControlView_sliderWidth, width);
                sliderHeight = typedArray.getDimension(R.styleable.LRSteeringControlView_sliderHeight, width);
                int cursorColor = typedArray.getColor(R.styleable.LRSteeringControlView_cursorColor, Color.BLACK);
                int scaleColor = typedArray.getColor(R.styleable.LRSteeringControlView_scaleColor, Color.BLACK);
                float scaleWidth = typedArray.getDimension(R.styleable.LRSteeringControlView_scaleWidth, 6);
                float cursorWidth = typedArray.getDimension(R.styleable.LRSteeringControlView_cursorWidth, 6);
                borderPaint.setColor(borderColor);
                silderPaint.setColor(sliderColor);
                cursorPaint.setColor(cursorColor);
                cursorPaint.setStrokeWidth(cursorWidth);
                scalePaint.setColor(scaleColor);
                scalePaint.setStrokeWidth(scaleWidth);
            }
        }
        setOnTouchListener(this);
        border = new RectF(0, 0, width, height);
        centX = width / 2;
        slider = new RectF(0, (height - sliderHeight) / 2, 0, height - (height - sliderHeight) / 2);
        availableStart = sliderWidth / 2;
        availableEnd = width - sliderWidth / 2;
        rangeWidth = availableEnd - availableStart;
        xOffSet = centX;

        positionAnimator = ValueAnimator.ofFloat(1);
        positionAnimator.addUpdateListener(animation -> {
            Float aFloat = (Float) animation.getAnimatedValue();
            movePoint(xOffSet + (centX - xOffSet) * aFloat);
        });

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(getActualSpec(widthMeasureSpec, true), getActualSpec(heightMeasureSpec, false));
    }


    public int getActualSpec(int spec, boolean width) {
        int mode = MeasureSpec.getMode(spec);
        int len = MeasureSpec.getSize(spec);
        if (mode == MeasureSpec.AT_MOST) {
            len = (int) (width ? this.width : this.height);
        }

        return MeasureSpec.makeMeasureSpec(len, mode);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawRect(border, borderPaint);
        // 将xOffSet复制到当前栈内，使用局部变量线程私有 ，防止计算过程更新导致矩形变形
        final float xOffSet = this.xOffSet;
        slider.left = xOffSet - sliderWidth / 2;
        slider.right = xOffSet + sliderWidth / 2;
        canvas.drawRect(slider, silderPaint);
        canvas.drawLine(xOffSet, 0, xOffSet, height, cursorPaint);
        canvas.drawLine(centX, 0, centX, height / 5, scalePaint);
        canvas.drawLine(centX, height * 4 / 5, centX, height , scalePaint);
    }


    @Override
    public boolean onTouch(View v, MotionEvent event) {

        float evx = event.getX(), evy = event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //滑动条外按压不生效
                if (evx < 0 || evx > width || evy < 0 || evy > height) {
                    break;
                }
            case MotionEvent.ACTION_MOVE:
                movePoint(evx);
                positionAnimator.cancel();
                break;
            case MotionEvent.ACTION_UP:
                positionAnimator.setDuration(100);
                positionAnimator.start();
                break;
        }
        return true;
    }

    private void movePoint(float evx) {
        // 左右
        if (evx < availableStart) {
            evx = availableStart;
        }
        if (evx > availableEnd) {
            evx = availableEnd;
        }

        final int value = (int) ((evx - availableStart) * 100 / rangeWidth);
        if (value == this.value) {
            return;
        }
        this.value = value;
        this.xOffSet = evx;

        invalidate();
        if (onValueChangeListener != null) {
            onValueChangeListener.onchange(value);
        }
    }

    public void setOnValueChangeListener(OnValueChangeListener onValueChangeListener) {
        this.onValueChangeListener = onValueChangeListener;
    }

    public interface OnValueChangeListener {
        void onchange(int value);
    }
}
